<!DOCTYPE html>
<style>
canvas {
  border: solid 1px;
  cursor: crosshair;
}
</style>
<h3>Low latency canvas experiment.</h3>
<p>While hovering the pointer over the canvases, the marker follows the position of the pointer.  The goal of latency reduction is to get the marker to follow as closely as possible the native mouse cursor painted by the OS. The rectangle below contains two superposed canvases, one is in low latency mode (green marker), the other is in regular mode (red marker). If low latency mode is working correctly, the green marker should follow closer than the red one.</p>
<p></p>
<div style="position:relative">
<canvas id="regular" width="2000" height="1000"></canvas>
<canvas id="low" width="2000" height="1000" style="position: absolute; top: 0px; left: 0px"></canvas>
</div>
<script>
let r_canvas = document.getElementById("regular");
let r_ctx = r_canvas.getContext("2d");

init(r_ctx);

let ll_canvas = document.getElementById("low");
let ll_ctx = ll_canvas.getContext("2d", {desynchronized: true});

function init(ctx) {
  ctx.fillStyle='#0000';
  ctx.fillRect(0, 0, r_canvas.width, r_canvas.height);
  ctx.lineWidth = 2;
}

let x = 0;
let y = 0;

let markerRadius = 0;


ll_canvas.addEventListener('pointermove', updateMarker);
// Hack: To trigger low latency input, we need to listen for 'pointerdown'
ll_canvas.addEventListener('pointerdown', () => {});

function updateMarker(e) {
  // clear previous marker
  let clearRadius = (2 * markerRadius > 20 ? 2 * markerRadius : 20) + r_ctx.lineWidth;
  ll_ctx.clearRect(x - clearRadius, y - clearRadius, 2 * clearRadius, 2 * clearRadius);
  r_ctx.clearRect(x - clearRadius, y - clearRadius, 2 * clearRadius, 2 * clearRadius);

  let client_rect = ll_canvas.getBoundingClientRect();

  x = e.clientX - client_rect.x;
  y = e.clientY - client_rect.y;

  // paint new marker
  r_ctx.strokeStyle = 'red';
  r_ctx.beginPath();
  r_ctx.moveTo(x - 20, y - 20);
  r_ctx.lineTo(x + 20, y + 20);
  r_ctx.moveTo(x + 20, y - 20);
  r_ctx.lineTo(x - 20, y + 20);
  r_ctx.stroke();

  ll_ctx.strokeStyle = 'green';
  ll_ctx.beginPath();
  ll_ctx.moveTo(x - 20, y - 20);
  ll_ctx.lineTo(x + 20, y + 20);
  ll_ctx.moveTo(x + 20, y - 20);
  ll_ctx.lineTo(x - 20, y + 20);
  ll_ctx.stroke();


  if (ll_ctx.commit)
    ll_ctx.commit();
}
</script>
